package com.huawang.mdesign.model.service.inter;

import com.huawang.business.command.CommandAddType;
import com.huawang.business.constants.*;
import com.huawang.business.dto.AddModelDTO;
import com.huawang.business.dto.ModelPropertyInfo;
import com.huawang.business.dto.diagram.*;
import com.huawang.business.entity.matrix.GeneralRetrospectMapNode;
import com.huawang.business.exception.AbortExecutionException;
import com.huawang.business.service.derivedspecification.IDerivedSpecificationService;
import com.huawang.business.service.judge.BusinessJudgeService;
import com.huawang.business.service.model.base.UmlService;
import com.huawang.business.service.model.core.*;
import com.huawang.business.service.model.core.add.IModelOperation;
import com.huawang.business.service.transaction.TransactionServiceImpl;
import com.huawang.business.util.InstanceVoUtils;
import com.huawang.business.vo.ElementType;
import com.huawang.business.vo.ModelResultVo;
import com.huawang.business.vo.PropertyInfoVo;
import com.huawang.business.vo.diagram.RelationMapNodeVo;
import com.huawang.business.vo.diagram.RelationMapRelationVo;
import com.huawang.business.vo.diagram.RelationStyleVo;
import com.huawang.core.definition.mof.UMLDefinitionConstants;
import com.huawang.core.definition.mof.cmof.reflection.impl.BasicRElement;
import com.huawang.core.definition.mof.instances.MetaClassInstance;
import com.huawang.core.semantics.entity.queryResult.MofResultContainer;
import com.huawang.core.semantics.entity.queryResult.QueryPropertyForm;
import com.huawang.core.semantics.entity.transaction.LocalTransaction;
import com.huawang.core.semantics.exception.LocalTransactionNotStartException;
import com.huawang.core.semantics.exception.TransactionNotExistingException;
import com.huawang.mdesign.model.service.dto.changeanalyse.EffectElementInfo;
import com.huawang.mdesign.model.service.facade.diagram.MetachainNavigationService;
import com.huawang.mdesign.model.service.facade.diagram.SimpleNavigationService;
import com.huawang.mdesign.model.service.facade.util.CheckAnalyseHandler;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.huawang.business.constants.ModelActionName.ADD_MODEL;

@Service
@Log4j2
public class DiagramMapService {
    @Autowired
    private InternalUmlService internalUmlService;

    @Autowired
    private UmlService umlService;

    @Autowired
    private InternalPropertyService internalPropertyService;

    @Autowired
    private InternalModelIconService internalModelIconService;

    @Autowired
    private SimpleNavigationService simpleNavigationService;

    @Autowired
    private MetachainNavigationService metachainNavigationService;

    @Autowired
    private ModelService modelService;

    @Autowired
    private InternalDiagramService internalDiagramService;

    @Autowired
    private ModelPropertyInfoService modelPropertyInfoService;

    @Autowired
    private TransactionServiceImpl transactionService;

    @Autowired
    private IDerivedSpecificationService derivedSpecificationService;

    @Autowired
    private ChangeAnalyseService changeAnalyseService;

    public List<ElementType> queryMapElementTypes(String projectId, String mapId) {
        List<MetaClassInstance> stereotypes;
        MetaClassInstance diagramMap = internalUmlService.fetchInstance(mapId, projectId);
        if (mapId != null && (internalUmlService.checkInstanceType(projectId, diagramMap,
                UMLDefinitionConstants.TableAndMatrix_RequirementRelationMap))) {
            List<String> stereotypeIds = internalUmlService.findSpecificIdsCascade(projectId,
                    UMLDefinitionConstants.SysML_AbstractRequirement, false);
            stereotypes = internalUmlService.fetchInstanceByIds(stereotypeIds, projectId);
            return internalDiagramService.parseMetaClassToElementType(projectId, stereotypes);

        }

        return internalDiagramService.queryAllElementType(projectId);
    }

    @NotNull
    public RelationCriterionDTO queryRelationCriterion(final String projectId, final String mapId) {
        com.huawang.business.dto.property.RelationCriterionDTO relationCriterionDto = internalPropertyService
                .queryRelationCriterion(projectId, mapId, UpdateRelationType.DIAGRAM.value());
        RelationCriterionDTO dto = new RelationCriterionDTO();
        dto.setProjectId(relationCriterionDto.getProjectId());
        dto.setMapId(relationCriterionDto.getInstanceId());
        dto.setImpliedRelations(relationCriterionDto.getImpliedRelations());
        dto.setMetachainNavigations(relationCriterionDto.getMetachainNavigations());
        dto.setSimpleNavigations(relationCriterionDto.getSimpleNavigations());
        return dto;
    }

    public ModelResultVo updateRelationCriterion(RelationCriterionDTO dto) {
        com.huawang.business.dto.property.RelationCriterionDTO relationsDto = new com.huawang.business.dto.property.RelationCriterionDTO();
        relationsDto.setProjectId(dto.getProjectId());
        relationsDto.setInstanceId(dto.getMapId());
        relationsDto.setSimpleNavigations(dto.getSimpleNavigations());
        relationsDto.setImpliedRelations(dto.getImpliedRelations());
        relationsDto.setMetachainNavigations(dto.getMetachainNavigations());
        relationsDto.setType(UpdateRelationType.DIAGRAM.value());
        return internalPropertyService.updateRelationCriterion(relationsDto);
    }

    public List<SelectedSimpleNavigation> querySelectedSimpleNavigation(String projectId, String mapId,
                                                                        String type) {
        return internalDiagramService.querySelectedSimpleNavigation(projectId, mapId, type);
    }

    @Nullable
    public RelationMapNodeVo queryMapTree(String projectId, String mapId, String rootId,
                                          @NotNull Integer level) {
        Map<String, MetaClassInstance> metaClassInstanceMap = internalUmlService.fetchInstances(Stream.of(mapId, rootId)
                .collect(Collectors.toList()), projectId);
        final MetaClassInstance relationMap = metaClassInstanceMap.get(mapId);
        if (relationMap == null) {
            return null;
        }

        MetaClassInstance root = metaClassInstanceMap.get(rootId);
        if (root == null) {
            root = internalUmlService.queryInstanceProperty(projectId,
                    relationMap, UMLDefinitionConstants.TableAndMatrix_DiagramMap_contextElement);
            if (root == null) {
                return null;
            }
        }

        final GeneralRetrospectMapNode node = internalDiagramService.getGeneralRetrospectMapNode(projectId, relationMap,
                root, level);
        if (node == null) {
            return null;
        }

        Map<String, RelationStyleVo> styleVos =
                internalDiagramService.queryRelationStyle(projectId, relationMap).stream()
                        .collect(Collectors.toMap(RelationStyleVo::getRelationKey,
                                it -> it, (a, b) -> a));
        return createRelationMapNodeVo(node, styleVos);
    }

    /**
     * 查询变更分析图树
     *
     * @param projectId
     * @param mapId
     * @param root
     * @param level
     * @return
     */
    @Nullable
    public RelationMapNodeVo queryAnalyseMapTree(String projectId,
                                                 String mapId,
                                                 @NotNull MetaClassInstance root,
                                                 @NotNull Integer level) {
        final MetaClassInstance relationMap = internalUmlService.fetchInstance(mapId, projectId);
        if (relationMap == null) {
            return null;
        }
        List<String> showScope = internalUmlService.queryListStringProperty(projectId, relationMap,
                UMLDefinitionConstants.TableAndMatrix_ChangeAnalysisMap_showScope);
        CheckAnalyseHandler checkAnalyseMethod = null;
        if (CollectionUtils.isNotEmpty(showScope)) {
            EffectElementInfo effectElementInfo = changeAnalyseService.queryEffectElements(projectId, relationMap);
            checkAnalyseMethod = CheckAnalyseHandler.init(effectElementInfo.getConfirmEffectElements(),
                    effectElementInfo.getNotEffectElements(), effectElementInfo.getMayEffectElement(),
                    showScope);
        }
        final GeneralRetrospectMapNode node = internalDiagramService.getGeneralRetrospectMapNode(projectId, relationMap,
                root, level);
        return createAnalyseMapNodeVo(node, checkAnalyseMethod);
    }

    private RelationMapNodeVo createRelationMapNodeVo(@NotNull GeneralRetrospectMapNode node, Map<String, RelationStyleVo> styleVos) {
        RelationMapNodeVo vo = new RelationMapNodeVo();
        vo.setInstanceId(node.getInstanceId());
        vo.setRelationVoList(node.getRelationNodes().stream().map(relation -> {
            RelationMapRelationVo relationVo = new RelationMapRelationVo();
            relationVo.setNextNode(createRelationMapNodeVo(relation.getNextNode(), styleVos));
            // 如果存在多个相同的relationKey则合并成1个
            Set<String> relationKeySet = new HashSet<>(relation.getRelationKey());
            if (relationKeySet.size() > 1) {
                relationVo.setRelationKey("multiplicity");
            } else {
                relationVo.setRelationKey(relation.getRelationKey().get(0));
            }

            List<String> labels =
                    relationKeySet.stream().map(styleVos::get).filter(Objects::nonNull)
                            .map(RelationStyleVo::getLabel).collect(Collectors.toList());
            relationVo.setLabels(labels);

            return relationVo;
        }).collect(Collectors.toList()));

        return vo;
    }

    public boolean checkNode(Set<String> confirmEffectElements,
                             Set<String> notEffectElements,
                             Set<String> includeElements,
                             Set<String> excludeElements,
                             List<String> scopes,
                             MetaClassInstance node) {
        if (scopes.contains(AnalyseNodeStateEnum.CONFIRM_EFFECT.value())) {
            includeElements.addAll(confirmEffectElements);
            excludeElements.removeAll(confirmEffectElements);
        }

        if (scopes.contains(AnalyseNodeStateEnum.NOT_EFFECT.value())) {
            includeElements.addAll(notEffectElements);
            excludeElements.removeAll(notEffectElements);
        }

        boolean flag = false;
        if (scopes.contains(AnalyseNodeStateEnum.MAY_EFFECT.value())) {
            flag = true;
        }

        return includeElements.contains(node.getId()) || (flag && excludeElements.contains(node.getId()));

    }

    private RelationMapNodeVo createAnalyseMapNodeVo(@NotNull GeneralRetrospectMapNode node,
                                                     @Nullable CheckAnalyseHandler checkHandler) {
        RelationMapNodeVo vo = new RelationMapNodeVo();
        vo.setInstanceId(node.getInstanceId());
        vo.setRelationVoList(node.getRelationNodes().stream()
                .filter(relation -> checkHandler == null || checkHandler.checkNode(relation.getNextNode().getInstanceId()))
                .map(relation -> {
                    RelationMapRelationVo relationVo = new RelationMapRelationVo();
                    relationVo.setNextNode(createAnalyseMapNodeVo(relation.getNextNode(), checkHandler));
                    if (relation.getRelationKey().size() > 1) {
                        relationVo.setRelationKey("multiplicity");
                    } else {
                        relationVo.setRelationKey(relation.getRelationKey().get(0));
                    }

                    return relationVo;
                }).collect(Collectors.toList()));

        return vo;
    }

    public List<MetaElementItem> queryMetaElementList(String projectId, String mapId, String key, String type) {
        MetaClassInstance relationMap = internalUmlService.fetchInstance(mapId, projectId);
        List<MetaClassInstance> metaClasses = null;
        if (relationMap != null) {
            metaClasses = getMetaClassOrStereotypeList(projectId, relationMap, key, type);
        }
        if (CollectionUtils.isEmpty(metaClasses)) {
            return Collections.emptyList();
        }

        QueryPropertyForm queryPropertyForm = internalUmlService.getQueryPropertyForm(metaClasses,
                UMLDefinitionConstants.NamedElement_name);
        MofResultContainer mofResultContainer = this.internalUmlService.queryProperty(projectId, queryPropertyForm);
        Map<String, String> iconMap = modelPropertyInfoService.queryIconBatch(projectId, metaClasses);
        return metaClasses.stream().map(metaClass -> {
            MetaElementItem item = new MetaElementItem();
            item.setMetaClassId(metaClass.getId());
            item.setIcon(iconMap.get(metaClass.getId()));
            if (BusinessJudgeService.isCreatedBySystem(metaClass)) {
                item.setLabel(mofResultContainer.queryStringProperty(metaClass.getId(),
                        UMLDefinitionConstants.NamedElement_name));
            } else {
                item.setLabel(metaClass.getId());
            }
            if (!internalUmlService.isMetaClass(projectId, metaClass)) {
                item.setType(ChainType.METASTEREOTYPE.value());
            } else {
                item.setType(ChainType.METACLASS.value());
            }

            return item;
        }).collect(Collectors.toList());
    }

    /**
     * 查询元类或构造性
     * 首行情况下（没有属性），查询当前元素的元类
     * 非首行情况下（有属性），当属性值是stereotype时，查询其顶层父类的metaProperty的所有子类和其所有子类；
     * 当属性是元类时，查询其所有子类，以及子类扩展的所以元素
     *
     * @param projectId
     * @param key
     * @param instance
     * @return java.util.List<com.huawang.model.instances.MetaClassInstance>
     * @author baibf
     * @date 2023/06/19 11:19
     */
    @NotNull
    private List<MetaClassInstance> getMetaClassOrStereotypeList(String projectId,
                                                                 @NotNull MetaClassInstance instance,
                                                                 String key,
                                                                 String updateRelationType) {
        if (StringUtils.isEmpty(key)) {
            // 1 处理当前行为首行的情况
            if (UpdateRelationType.DERIVED_PROPERTY_EXPRESSION.value().equals(updateRelationType)) {
                MetaClassInstance owner = internalUmlService.queryInstanceProperty(projectId, instance,
                        UMLDefinitionConstants.Element_owner);
                if (owner == null) {
                    return Collections.emptyList();
                }

                List<MetaClassInstance> targets = internalUmlService.queryListInstanceProperty(projectId, owner,
                        UMLDefinitionConstants.Customization_Customization_customizationTarget);
                if (CollectionUtils.isEmpty(targets)) {
                    return Collections.emptyList();
                }

                return queryElementMetaClass(projectId, targets.get(0));
            } else if (UpdateRelationType.RULE.value().equals(updateRelationType)) {
                return queryElementMetaClass(projectId, instance);
            } else {
                return getNoDerivedInstances(projectId, instance);
            }
        } else {
            // 2 处理当前行非首行的情况
            return getNofirstMetaClassInstances(projectId, key);
        }
    }

    @NotNull
    private List<MetaClassInstance> getNofirstMetaClassInstances(String projectId, String key) {
        MetaClassInstance type = queryValidMetaPropertyType(projectId, key);
        if (type == null) {
            return Collections.emptyList();
        }

        return queryChainMetaModel(projectId, type);
    }

    @NotNull
    private List<MetaClassInstance> queryChainMetaModel(String projectId, MetaClassInstance type) {
        List<String> specificsCascade;
        List<String> generalCascade;
        String baseClass;
        if (internalUmlService.checkInstanceType(projectId, type, UMLDefinitionConstants.Stereotype)) {
            // 2.1 处理上一行“属性”的类型是构造型的情况
            String basePropertyId = internalUmlService.getBaseProperty(projectId, type);
            baseClass = internalUmlService.queryPropertyTypeId(projectId, basePropertyId);
            if (baseClass != null) {
                specificsCascade = internalUmlService.findSpecificIdsCascade(projectId,
                        Stream.of(baseClass).collect(Collectors.toList()), false);
                generalCascade = internalUmlService.findGeneralIdsCascade(projectId, baseClass, false);
            } else {
                specificsCascade = new ArrayList<>();
                generalCascade = new ArrayList<>();
            }

        } else {
            // 2.2 处理上一行“属性”的类型是元类的情况
            specificsCascade = internalUmlService.findSpecificIdsCascade(projectId, type.getId(), false);
            generalCascade = internalUmlService.findGeneralIdsCascade(projectId, type.getId(), false);
            baseClass = type.getId();
        }
        log.info("baseClass:{}", baseClass);
        // 1.如果baseClass的父类与子类均为空,直接return
        if (CollectionUtils.isEmpty(generalCascade) && CollectionUtils.isEmpty(specificsCascade)) {
            return new ArrayList<>();
        }

        // 2.查询baseClass及其父类与子类的模型
        List<String> allBaseClass = Stream.of(specificsCascade, generalCascade, Collections.singletonList(baseClass))
                .flatMap(Collection::stream).collect(Collectors.toList());
        Map<String, MetaClassInstance> allBaseClassInstanceMap = this.internalUmlService.fetchInstances(allBaseClass, projectId);
        List<MetaClassInstance> allBaseClassInstanceList = allBaseClass.stream().map(allBaseClassInstanceMap::get)
                .filter(Objects::nonNull).collect(Collectors.toList());
        // 3.查询baseClass及其子类能够应用的构造型列表
        List<String> queryApplicableStereotypeIds = Stream.of(specificsCascade, Collections.singletonList(baseClass))
                .flatMap(Collection::stream).collect(Collectors.toList());
        List<String> applicableStereoTypeIds = queryApplicableStereotypeIds.stream().flatMap(instanceId -> {
            return internalUmlService.getMetaClassInstanceApplicableStereotype(projectId, allBaseClassInstanceMap.get(instanceId)).stream();
        }).collect(Collectors.toList());
        List<MetaClassInstance> applicableStereoTypes = internalUmlService.fetchInstanceByIds(applicableStereoTypeIds, projectId);
        allBaseClassInstanceList.addAll(applicableStereoTypes);
        // 4.将baseClass移至List首位
        int baseClassIndex = allBaseClassInstanceList.indexOf(allBaseClassInstanceMap.get(baseClass));
        allBaseClassInstanceList.add(0, allBaseClassInstanceList.remove(baseClassIndex));
        return allBaseClassInstanceList.stream().distinct().collect(Collectors.toList());
    }

    @NotNull
    private List<MetaClassInstance> getNoDerivedInstances(String projectId, @NotNull MetaClassInstance instance) {
        Set<String> givenTypes = internalUmlService.getGivenTypes(projectId, instance);
        if (givenTypes.contains(UMLDefinitionConstants.TableAndMatrix_DiagramTable)) {
            List<MetaClassInstance> rowElementTypeList = internalUmlService.queryListInstanceProperty(projectId, instance,
                    UMLDefinitionConstants.TableAndMatrix_DiagramTable_rowElementType);
            if (CollectionUtils.isEmpty(rowElementTypeList)) {
                log.error("DiagramTable的rowElementType不存在, DiagramTableId:{}", instance.getId());
                return Collections.emptyList();
            }
            return rowElementTypeList.stream().distinct().flatMap(it -> queryChainMetaModel(projectId, it).stream())
                    .distinct().collect(Collectors.toList());
        } else if (givenTypes.contains(UMLDefinitionConstants.TableAndMatrix_DiagramMatrix)) {
            List<MetaClassInstance> columnElementTypes = internalUmlService.queryListInstanceProperty(projectId, instance,
                    UMLDefinitionConstants.TableAndMatrix_DiagramMatrix_columnElementType);
            List<MetaClassInstance> rowElementTypes = internalUmlService.queryListInstanceProperty(projectId, instance,
                    UMLDefinitionConstants.TableAndMatrix_DiagramMatrix_rowElementType);
            if (CollectionUtils.isEmpty(columnElementTypes) && CollectionUtils.isEmpty(rowElementTypes)) {
                log.error("DiagramMatrix的rowElementType不存在, DiagramMatrixId:{}", instance.getId());
                return Collections.emptyList();
            }
            Set<MetaClassInstance> types = new HashSet<>();
            types.addAll(rowElementTypes);
            types.addAll(columnElementTypes);
            return types.stream().flatMap(it -> queryChainMetaModel(projectId, it).stream()).distinct()
                    .collect(Collectors.toList());
        } else {
            MetaClassInstance context = internalUmlService.queryInstanceProperty(projectId, instance,
                    UMLDefinitionConstants.TableAndMatrix_DiagramMap_contextElement);
            if (context == null) {
                log.error("DiagramMap的context属性不存在，mapId:{}", instance);
                return Collections.emptyList();
            }
            List<MetaClassInstance> stereotypes = internalUmlService.queryListInstanceProperty(projectId, context,
                    UMLDefinitionConstants.Element_appliedStereotype);
            String typeId;
            if (CollectionUtils.isNotEmpty(stereotypes)) {
                typeId = stereotypes.get(0).getId();
            } else {
                typeId = context.getMetaClass().getId();
            }
            MetaClassInstance type = internalUmlService.fetchInstance(typeId, projectId);
            if (type == null) {
                log.error("模型id不存在:{}", typeId);
                return new ArrayList<>();
            }
            return queryChainMetaModel(projectId, type);
        }
    }

    @Nullable
    private MetaClassInstance queryValidMetaPropertyType(String projectId, String propertyId) {
        MetaClassInstance type = internalUmlService.queryPropertyType(projectId, propertyId);
        if (type == null) {
            return null;
        }

        if (!internalUmlService.isMetaModel(projectId, type) ||
                internalUmlService.checkInstanceType(projectId, type, UMLDefinitionConstants.Enumeration)) {
            return null;
        }
        return type;
    }

    public boolean canInsertChainByProperty(String projectId, String propertyId) {
        MetaClassInstance type = queryValidMetaPropertyType(projectId, propertyId);
        return type != null;
    }

    @NotNull
    public List<MetaClassInstance> queryElementMetaClass(String projectId, MetaClassInstance type) {
        List<String> metaClassIds = new ArrayList<>();
        if (internalUmlService.checkInstanceType(projectId, type, UMLDefinitionConstants.Stereotype)) {
            List<MetaClassInstance> baseClasses = internalUmlService.getSelfBasePropertyListFromInstance(projectId,
                    type);
            List<String> generalIds = baseClasses.stream().flatMap(baseClass -> internalUmlService.getGeneralIdsCascade(projectId,
                    baseClass.getId()).stream()).collect(Collectors.toList());
            metaClassIds.addAll(generalIds);
        }
        metaClassIds.addAll(internalUmlService.getGeneralIdsCascade(projectId, type.getId()));
        return this.internalUmlService.fetchInstanceByIds(metaClassIds, projectId);
    }

    public List<PropertyInfoVo> queryChainProperty(@NotNull final String projectId,
                                                   @NotNull final String typeId,
                                                   @Nullable final String type) {
        List<PropertyInfoVo> propertyInfoVos;
        if (UpdateRelationType.RULE.value().equals(type)) {

            List<String> propertyNames = internalUmlService.queryMetaClassMetaPropertyNamesWithAllGeneral(
                    Collections.singletonList(typeId), projectId,
                    false, false, false);

            List<MetaClassInstance> properties = this.internalUmlService.fetchInstanceByIds(propertyNames, projectId);

            propertyInfoVos = convertPropertyToPropertyInfoVo(projectId, properties);
        } else {
            List<String> propertyNames = internalUmlService.queryMetaClassMetaPropertyNamesWithAllGeneral(
                    Collections.singletonList(typeId), projectId,
                    true, true, true);
            List<MetaClassInstance> properties = this.internalUmlService.fetchInstanceByIds(propertyNames, projectId);

            propertyInfoVos = convertPropertyToPropertyInfoVo(projectId, properties);
            //派生属性
            List<MetaClassInstance> derivedProperties =
                    internalUmlService.fetchInstanceByIds(derivedSpecificationService.queryDerivedPropertiesByIds(projectId,
                            Stream.of(typeId).collect(Collectors.toList())), projectId);
            List<ModelPropertyInfo> models = modelPropertyInfoService.createModelPropertyInfoList(projectId, derivedProperties,
                    Stream.of(UMLDefinitionConstants.TypedElement_type, UMLDefinitionConstants.NamedElement_name)
                            .collect(Collectors.toList()));
            QueryPropertyForm queryPropertyForm = internalUmlService.getQueryPropertyForm(derivedProperties, UMLDefinitionConstants.NamedElement_name);
            MofResultContainer mofResultContainer = this.internalUmlService.queryProperty(projectId, queryPropertyForm);
            List<PropertyInfoVo> derivedPropertyInfoVos = models.stream()
                    .map(it -> {
                        PropertyInfoVo vo = new PropertyInfoVo();
                        vo.setName(mofResultContainer.queryStringProperty(it.getInstanceId(), UMLDefinitionConstants.NamedElement_name));
                        vo.setKey(it.getInstanceId());
                        return vo;
                    }).collect(Collectors.toList());
            propertyInfoVos.addAll(derivedPropertyInfoVos);
            return propertyInfoVos;
        }

        return propertyInfoVos;

    }

    @NotNull
    private List<PropertyInfoVo> convertPropertyToPropertyInfoVo(String projectId, List<MetaClassInstance> properties) {
        final QueryPropertyForm queryPropertyForm = this.internalUmlService
                .getQueryPropertyForm(
                        properties,
                        Stream.of(UMLDefinitionConstants.TypedElement_type, UMLDefinitionConstants.MultiplicityElement_upper)
                                .collect(Collectors.toList())
                );
        final MofResultContainer mofResultContainer = this.internalUmlService.queryProperty(projectId, queryPropertyForm);
        final Set<String> metaPropertyNames = properties.stream()
                .filter(it -> this.internalUmlService.isMetaProperty(projectId, it))
                .map(BasicRElement::getId)
                .collect(Collectors.toSet());
        return properties.stream()
                .map(it -> {
                    PropertyInfoVo vo = new PropertyInfoVo();
                    vo.setName(internalPropertyService
                            .queryOrInitPropertyLabel(projectId, it, metaPropertyNames.contains(it.getId()), mofResultContainer)
                    );
                    vo.setKey(it.getId());
                    return vo;
                }).collect(Collectors.toList());
    }

    public List<NewNodeDTO> queryNewNodeList(String projectId, String sourceId, String mapId) {
        Map<String, MetaClassInstance> metaClassInstanceMap = internalUmlService.fetchInstances(Stream.of(mapId, sourceId)
                .collect(Collectors.toList()), projectId);
        MetaClassInstance relationMap = metaClassInstanceMap.get(mapId);
        MetaClassInstance source = metaClassInstanceMap.get(sourceId);
        if (relationMap == null || source == null) {
            throw AbortExecutionException.build(ErrorCode.MODEL_NO_EXIST);
        }

        Map<String, List<NewRelationDTO>> incoming = new HashMap<>();
        Map<String, List<NewRelationDTO>> outgoing = new HashMap<>();
        Map<String, NewNodeDTO> map = new HashMap<>();
        RelationCriterionDTO dto = queryRelationCriterion(projectId, mapId);

        List<MetaClassInstance> elementTypes = internalUmlService.queryListInstanceProperty(projectId, relationMap,
                UMLDefinitionConstants.TableAndMatrix_DiagramMap_elementTypes);
        List<String> elementMetaClassIds = elementTypes.stream()
                .flatMap(it -> internalUmlService.queryMetaClassByTypeUri(projectId, it.getId()).stream())
                .collect(Collectors.toList());
        List<MetaClassInstance> elementMetaClass = internalUmlService.fetchInstanceByIds(elementMetaClassIds, projectId)
                .stream()
                .filter(metaClass -> BooleanUtils.isFalse(internalUmlService.getIsAbstract(projectId, metaClass)))
                .collect(Collectors.toList());

        List<String> simpleNavigationKey = dto.getSimpleNavigations().stream().map(SimpleNavigation::getKey)
                .collect(Collectors.toList());

        // 批量查询simpleNavigationKey的模型实例
        Map<String, MetaClassInstance> simpleNavigationKeyInstanceMap = this.internalUmlService
                .fetchInstances(simpleNavigationKey, projectId);

        dto.getSimpleNavigations().stream()
                .flatMap(simpleNavigation -> simpleNavigationService.queryNewNode(projectId, source, simpleNavigation
                        , elementMetaClass, simpleNavigationKeyInstanceMap).stream())
                .forEach(newNodeDto -> fillNewNodeMap(incoming, outgoing, map, newNodeDto));
        dto.getMetachainNavigations().stream()
                .flatMap(metachainNavigation -> metachainNavigationService.queryNewNode(projectId,
                        metachainNavigation, elementTypes).stream())
                .forEach(newNodeDto -> fillNewNodeMap(incoming, outgoing, map, newNodeDto));
        return new ArrayList<>(map.values());
    }

    private void fillNewNodeMap(Map<String, List<NewRelationDTO>> incoming, Map<String, List<NewRelationDTO>> outgoing, Map<String, NewNodeDTO> map, NewNodeDTO newNodeDto) {
        map.putIfAbsent(newNodeDto.getMetaClassId(), newNodeDto);
        List<NewRelationDTO> incomingResult = incoming.computeIfAbsent(newNodeDto.getMetaClassId(),
                k -> new ArrayList<>());
        incomingResult.addAll(newNodeDto.getIncoming());
        List<NewRelationDTO> outgoingResult = outgoing.computeIfAbsent(newNodeDto.getMetaClassId(), k -> new ArrayList<>());
        outgoingResult.addAll(newNodeDto.getOutgoing());
    }

    public ModelResultVo createNewNode(CreateNewNodeDTO createNewNodeDto) {
        final String projectId = createNewNodeDto.getProjectId();
        MetaClassInstance source = internalUmlService.fetchInstance(createNewNodeDto.getSourceId(), projectId);
        if (source == null) {
            throw AbortExecutionException.build(ErrorCode.MODEL_NO_EXIST);
        }

        ModelResultVo modelResultVo = new ModelResultVo();
        LocalTransaction transaction = transactionService.createTransaction(projectId, ADD_MODEL);
        try {

            AddModelDTO addModelDto = new AddModelDTO();
            addModelDto.setProjectId(projectId);
            addModelDto.setMetaclass(createNewNodeDto.getMetaclass());
            addModelDto.setParentId(createNewNodeDto.getSourceId());
            addModelDto.setType(CommandAddType.MODEL.getCode());
            addModelDto.setApplyStereotypes(createNewNodeDto.getApplyStereotypes());
            final IModelOperation modelOperation = umlService.fetchModelOperation(addModelDto.getMetaclass(),
                    addModelDto.getOperation());
            MetaClassInstance model = modelService.addModel(addModelDto, modelOperation);
            CreateNewRelationDTO createNewRelationDto = createNewNodeDto.getRelationDto();
            if (createNewRelationDto.getType().equals(SimpleNavigationGroupEnum.RELATION.value())) {
                AddModelDTO addRelationShipDto = new AddModelDTO();
                addRelationShipDto.setProjectId(projectId);
                addRelationShipDto.setMetaclass(createNewRelationDto.getMetaclass());
                addRelationShipDto.setParentId(createNewNodeDto.getSourceId());
                addRelationShipDto.setType(CommandAddType.MODEL.getCode());
                addRelationShipDto.setApplyStereotypes(createNewRelationDto.getApplyStereotypes());
                if (Objects.equals(createNewRelationDto.getDirect(), DirectEnum.IN.getName())) {
                    addRelationShipDto.setSource(model.getId());
                    addRelationShipDto.setTarget(createNewNodeDto.getSourceId());
                } else {
                    addRelationShipDto.setSource(createNewNodeDto.getSourceId());
                    addRelationShipDto.setTarget(model.getId());
                }

                final IModelOperation relationShipOperation = umlService.fetchModelOperation(addRelationShipDto.getMetaclass(),
                        addRelationShipDto.getOperation());
                modelService.addModel(addRelationShipDto, relationShipOperation);
            } else {
                umlService.appendModel(projectId, source.getId(), createNewRelationDto.getKey(), model);
            }

            transactionService.commit(projectId);
            modelResultVo.setInstanceId(model.getId());
            InstanceVoUtils.fillModelResultVo(modelResultVo, transaction);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.ADD_MODEL_ERROR, e);
        }

        return modelResultVo;
    }

}
